/**
 * domgen.js
 * 
 * DOM generation tool for easy dynamic content generation via 
 * JavaScript. Generates DOM elements from dictionary specification 
 * similar to HTML and eliminates the need for cumbersome DOM 
 * JavaScript API.
 * 
 * Separated from Ion project: http://bitbucket.org/jtoivola/ion/
 * 
 * @url		 : http://bitbucket.org/jtoivola/domgen/
 * @copyright: mFabrik Ltd., Jussi Toivola
 * @license  : MIT
 * 
 * Example DOM generation:
    
    // generate returns the DOM elements with ids.
	var elements = domgen.generate( domgen.get('body')[0],
		[
			// This is the tag of the first element
			"div",
			// These are the attributes for the first element
			{
				id : 'mytag'
			},
			// These are the children of the first element
			[
				'input',
				{
					type : 'password'   
				}
			],
			// Tag of second elem
			"div",
			{
				// _ is used to separate element object attributes from tag attributes.
				// See domgen.setattrs
				id : 'content',
				_innerHTML : 'My content inside the div' 
			},
			// Tag of third elem
			"div"
	   ]
	);
    // You can access and manipulate the returned elements
    alert(elements.content.innerHTML)
    
	Generates:
	<div id="mytag">
		<input type="password"></input>        
	</div>
	<div>My content inside the div</div>
	<div></div>
 */

var domgen = {
    get : function(id){
        var marker = id[0];
        if( marker === "#"){
            return document.getElementById(id.slice(1));
        }
        else if( marker === "."){
            return document.getElementsByClassName(id.slice(1));
        }
        else{
            return document.getElementsByTagName(id);
        }
    },
    
    /** Append one or more elements to another. 
     */
    append : function(aParent, aElem){
        if(!aElem.length){
            aParent.appendChild(aElem); 
        }
        else{
            var l = aElem.length;
            for(var i=0;i<l;i++){
                aParent.appendChild(aElem[i]);
            }   
        }
    },
    /** Set attributes for DOM element
     * If attribute starts with '_' it is assigned as <elem>.<attr>
     * Normally it is assigned with <elem>.setAttribute.
     * 
     * Example: domgen.setattrs(aElem,{'id' : 'myid'})
     * 
     * @param {Object} aElem
     * @param {Object} aAttrs
     */
    setattrs : function(aElem, aAttrs){
        for( var a in aAttrs ){
            if( a[0] === "_" ){                            
                aElem[a.slice(1)] = aAttrs[a];
            }
            else {
                aElem.setAttribute(a,aAttrs[a]);
            }
        }
    },
    /** Create a new element of given node name and attributes 
     * See setattrs for more information about attributes.
     * 
     * Example: domgen.create('div',{'id' : 'mydiv'})
     * 
     * @param {Object} aNodeName
     * @param {Object} aAttrs
     * @return DOM element
     */
    create : function(aNodeName, aAttrs){
        var elem = document.createElement(aNodeName);
        if(aAttrs){
            domgen.setattrs(elem,aAttrs);
        }
        return elem;
    },
    /** Generate HTML from JSON specification
     * @param elem: Parent element
     * @param spec: The dom specification
     * @param args: Optional parameters.
     *          {
     *              true : false, // Erase old content from target element 
     *          }
     * @return  The elements, which had id defined in the spec mapped as
     *          <id> : <element>
     * 
     * 
     */
    generate : function(parent, spec, args){
        
        var create = domgen.create;
        var setattrs = domgen.setattrs;
        var clean = true;
        if( args ){
            clean = args.clean === undefined ? clean : args.clean;
        }
        
        if( clean ){
            parent.innerText = "";
        }
        
        // To return the elements, which had id defined in the spec.
        var self = this;
        var idmap     = {};
        self.elemstack = [parent];
        function top(){
            return self.elemstack[self.elemstack.length-1];
        }
        
        // Define the generator function first time only
        if(!this.generator){
            function generator(itemspec){
                var parent = top();
                
                for( var i in itemspec ){
                    var item = itemspec[i];
                    if(typeof item === 'string')
                    {
                        // Name of the tag.
                        var elem = create(item);
                        self.elemstack.push(elem);
                        parent.appendChild(elem);
                    }
                    else if( item.length ){
                        generator(item);                    
                    }
                    // Set attributes of the current item
                    else{
                    
                        var elem = top();
                        setattrs(elem, item);
    
                        // Add to mapping if id is defined
                        if(item.id){
                            idmap[item.id] = elem;
                        }
                    }
                }             
                self.elemstack.pop();
            }
            this.generator = generator;
        }
        
        this.generator(spec);
        
        return idmap;
    }
};
